package xyz.hzxiao.config.interceptor;

import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import xyz.hzxiao.annotation.EncryptedColumn;
import xyz.hzxiao.annotation.EncryptedTable;
import xyz.hzxiao.utils.DesensitizationUtils;
import xyz.hzxiao.utils.Sm4Utils;

import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 解密拦截器
 *
 * @author ：FuXx
 * @className : xyz.hzxiao.config.interceptor.DecryptInterceptor
 * @since ：2023-08-18
 */
@Intercepts({
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
@Component
public class DecryptInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object proceed = invocation.proceed();
        if (!(proceed instanceof List)) {
            return proceed;
        }
        List<?> results = (List<?>) proceed;
        for (Object result : results) {
            if (!isExistAnnotations(result.getClass())) {
                return proceed;
            }
            // 获取加密字段
            decrypt(result);
        }
        return proceed;
    }

    private void decrypt(Object o) {
        Field[] declaredFields = o.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            EncryptedColumn encryptedColumn = field.getAnnotation(EncryptedColumn.class);
            Optional.ofNullable(encryptedColumn)
                    .ifPresent(e -> {
                        field.setAccessible(Boolean.TRUE);
                        try {
                            Object var = field.get(o);
                            if (var instanceof String) {
                                String encryptValue = (String) var;
                                String decryptValue = Sm4Utils.decryptEcb(encryptValue);
                                field.set(o, DesensitizationUtils.replace(decryptValue, e.mask(), e.prefix(), e.suffix()));
                            }
                        } catch (Exception ex) {
                            throw new RuntimeException(ex);
                        }
                    });
        }
    }

    private Boolean isExistAnnotations(Class<?> clazz) {
        return Objects.nonNull(AnnotationUtils.getAnnotation(clazz, EncryptedTable.class));
    }

}
